🎖️GitЯра🎖️
Commit 057d5bb778a72cf4359abc7fae904d587cdc90a2
Parents : f0e1269
Author : James Rich <2199651+jamesarich@users.noreply.github.com>
Signature : Signature validation error
Date : 2026-05-18T06:24:09-05:00
Committer : GitHub <noreply@github.com>
Date : 2026-05-18T11:24:09Z
fix(database): make withDb retry logic resilient to varying close messages (#5474)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Changes
1 files changed, 22 insertions(+), 7 deletions(-)
Diff
diff --git a/core/database/src/commonMain/kotlin/org/meshtastic/core/database/DatabaseManager.kt b/core/database/src/commonMain/kotlin/org/meshtastic/core/database/DatabaseManager.kt
index e96ce887cb..42dd56a6af 100644
--- a/core/database/src/commonMain/kotlin/org/meshtastic/core/database/DatabaseManager.kt
+++ b/core/database/src/commonMain/kotlin/org/meshtastic/core/database/DatabaseManager.kt
@@ -169,7 +169,7 @@ open class DatabaseManager(
private val limitedIo = dispatchers.io.limitedParallelism(4)
- /** Execute [block] with the current DB instance. */
+ /** Execute [block] with the current DB instance. Retries once if the pool closes during a DB switch. */
@Suppress("TooGenericExceptionCaught")
override suspend fun <T> withDb(block: suspend (MeshtasticDatabase) -> T): T? = withContext(limitedIo) {
val db = _currentDb.value ?: return@withContext null
@@ -180,18 +180,33 @@ open class DatabaseManager(
} catch (e: CancellationException) {
throw e // Preserve structured concurrency cancellation propagation.
} catch (e: Exception) {
- // If the connection pool was closed between capturing `db` and executing the query
- // (e.g., during a database switch), retry once with the current DB instance.
- if (e.message?.contains("Connection pool is closed") == true) {
- Logger.w { "withDb: connection pool closed, retrying with current DB" }
- val retryDb = _currentDb.value ?: return@withContext null
- block(retryDb)
+ // If the active database switched while we held a reference to the old one,
+ // and the exception indicates a closed pool/connection, retry with the new DB.
+ val retryDb = _currentDb.value
+ if (retryDb != null && retryDb !== db && isDbClosedException(e)) {
+ Logger.w { "withDb: database closed during switch (${e.message}), retrying with current DB" }
+ try {
+ block(retryDb)
+ } catch (retryEx: Exception) {
+ retryEx.addSuppressed(e)
+ throw retryEx
+ }
} else {
throw e
}
}
}
+ private fun isDbClosedException(e: Exception): Boolean = generateSequence<Throwable>(e) { it.cause }
+ .any { throwable ->
+ val msg = throwable.message?.lowercase() ?: return@any false
+ "closed" in msg && DB_TERMS.any { it in msg }
+ }
+
+ private companion object {
+ val DB_TERMS = listOf("pool", "database", "connection", "sqlite")
+ }
+
/**
* Returns true if a database exists for the given device address. Android Room stores DB files without an
* extension; JVM/iOS append `.db`. We check both to stay platform-agnostic.
Served by rngit 1.5.4 - Generated in 0.13s